package sg.edu.nus.iss.billing.dao.subscription;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import sg.edu.nus.iss.billing.common.DbUtil;
import sg.edu.nus.iss.billing.common.Util;
import sg.edu.nus.iss.billing.common.exception.BadDaoCallException;
import sg.edu.nus.iss.billing.common.exception.BadDbCallException;
import sg.edu.nus.iss.billing.common.exception.InvalidParamsException;
import sg.edu.nus.iss.billing.vo.subscription.CableTvVO;
import sg.edu.nus.iss.billing.vo.subscription.SubscriptionVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.ChannelFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.StandardChannelFeatureVO;


public class SubscriptionDAO implements ISubscriptionDAO, IPlanDAO {
	private ArrayList<String> data = null;
	private final static String SUBSCRIPTION_PATH = "data//subscription.txt";
	private final static String PLAN_PATH = "data//plans.txt";
	
	public SubscriptionDAO() {
		try {
			data = (ArrayList<String>) DbUtil.loadDb(SUBSCRIPTION_PATH);
		} catch (BadDbCallException e) {
			data = new ArrayList<String>();
			e.printStackTrace();
		}
	}
	
	private boolean subscriptionExist(String accountNo, String subId) {
		SubscriptionVO s = new SubscriptionVO();
		for(int i=0;i<data.size();i++){
			try {
				s.setParameters(data.get(i));
				if (s.getAccNo().equals(accountNo) && s.getSubsId().equals(subId)) {
					return true;
				}
			} catch (InvalidParamsException e) {
				e.printStackTrace();
			}
		}
		return false;
	}
	
	private void createSubscrptn (SubscriptionVO subscription) throws BadDaoCallException {
		if (subscriptionExist(subscription.getAccNo(), subscription.getSubsId())) {
			throw new BadDaoCallException ("Subscription already exists!");
		} else {
			data.add(subscription.serialised());
			try {
				DbUtil.saveDb(SUBSCRIPTION_PATH, data);
			} catch (BadDbCallException e) {
				throw new BadDaoCallException("Unable to save to db. " + e.getMessage());
			}
		}
	}
	
	private void terminateSubscription (String subId, String status, Date endDate ) {
		for (int i=0; i<data.size(); i++) {
			SubscriptionVO sub = new SubscriptionVO();
			try {
				sub.setParameters(data.get(i));
				if (sub.getSubsId().equals(subId)) {
					try {
						sub = (SubscriptionVO) Util.getSubscriptionVOMap().get(sub.getName()).newInstance();
						sub.setParameters(data.get(i));
						sub.setStatus(status);
						sub.setEndDate(endDate);
						data.set(i, sub.serialised());
						DbUtil.saveDb(SUBSCRIPTION_PATH, data);
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (BadDbCallException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					break;
				}
			} catch (InvalidParamsException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void updateSubscptn(SubscriptionVO subscription) throws BadDaoCallException {
		for (int i=0; i<data.size(); i++) {
			SubscriptionVO sub = new SubscriptionVO();
			try {
				sub.setParameters(data.get(i));
				if (sub.getSubsId().equals(subscription.getSubsId())) {
					data.set(i, subscription.serialised());
					try {
						DbUtil.saveDb(SUBSCRIPTION_PATH, data);
						return;
					} catch (BadDbCallException e1) {
						throw new BadDaoCallException ("Unable to save to db. " + e1.getMessage());
					}
				}
			} catch (InvalidParamsException e) {
				e.printStackTrace();
			}
		}
		throw new BadDaoCallException("Entry not found. Failed to update. Subscription:" +subscription.getSubsId());
	}
	
	public List<SubscriptionVO> getSubscriptionForAcct (String accountNo) {
		ArrayList<SubscriptionVO> results = new ArrayList<SubscriptionVO>();
		for (int i=0; i<data.size(); i++) {
			SubscriptionVO sub = new SubscriptionVO();
			try {
				sub.setParameters(data.get(i));
				if (sub.getAccNo().equals(accountNo)) {
					if(Util.getSubscriptionVOMap().containsKey(sub.getName())) {
						try {
							sub = (SubscriptionVO) Util.getSubscriptionVOMap().get(sub.getName()).newInstance();
							sub.setParameters(data.get(i));
							results.add(sub);
						} catch (InstantiationException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InvalidParamsException e) {
							e.printStackTrace();
						}
					}
				}
			} catch (InvalidParamsException e) {
				e.printStackTrace(); //skip invalid entry
			}
		}
		return results;
	}
	
	public void setSubscriptionStatus (String subId, String status) {
		terminateSubscription(subId, status, Util.getSystemDate());
	}
	
	public void createSubscription (SubscriptionVO subscription) {
		try {
			createSubscrptn(subscription);
		} catch (BadDaoCallException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void updateSubscription(SubscriptionVO subscription) throws BadDaoCallException {
		updateSubscptn(subscription);
	}
	

	@Override
	public SubscriptionVO getSubscriptionPlan(String name) {
		SubscriptionVO plan = null;
		try {
			ArrayList<String> serialisedPlans = (ArrayList<String>) DbUtil.loadDb(PLAN_PATH);
			for (int i=0; i<serialisedPlans.size(); i++) {
				try {
					SubscriptionVO sub = new SubscriptionVO();
					sub.setParameters(serialisedPlans.get(i));
					if (sub.getName().equals(name)) {
						try {
							sub = (SubscriptionVO) Util.getSubscriptionVOMap().get(sub.getName()).newInstance();
							sub.setParameters(serialisedPlans.get(i));
							plan = sub;
						} catch (InstantiationException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}
					}
				} catch (InvalidParamsException e) {
					e.printStackTrace(); //skip invalid entry
				}
			}
		} catch (BadDbCallException e) {
			e.printStackTrace();
		}
		return plan;
	}

	@Override
	public List<SubscriptionVO> getAllSubscriptionPlan() {
		ArrayList<SubscriptionVO> plans = new ArrayList<SubscriptionVO>();
		try {
			ArrayList<String> serialisedPlans = (ArrayList<String>) DbUtil.loadDb(PLAN_PATH);
			for (int i=0; i<serialisedPlans.size(); i++) {
				try {
					SubscriptionVO sub = new SubscriptionVO();
					sub.setParameters(serialisedPlans.get(i));
					try {
						sub = (SubscriptionVO) Util.getSubscriptionVOMap().get(sub.getName()).newInstance();
						sub.setParameters(serialisedPlans.get(i));
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
					plans.add(sub);
				} catch (InvalidParamsException e) {
					e.printStackTrace(); //skip invalid entry
				}
			}
		} catch (BadDbCallException e) {
			e.printStackTrace();
		}
		return plans;
	}
	
	public void test () {
		
		// Get SubscriptionPlan
		ArrayList<SubscriptionVO> plans = (ArrayList<SubscriptionVO>) getAllSubscriptionPlan();
		
		int numOfRun = 50;
		for (int i=0; i<numOfRun; i++) {
			// Create Subscription
			String accountId = "ACCT"+Util.generateRandomNumer();
			Date startDate = Util.getRandomDateAgo(15);
			
			for (int j=0; j<plans.size(); j++) {
				SubscriptionVO plan = plans.get(j);
				if (plan.getName().equals(Util.SUBSCRIPTIONVO_CABLETV)) {
					CableTvVO cable = new CableTvVO();
					cable.setAccNo(accountId);
					cable.setSubsId("S"+Util.generateRandomNumer());
					cable.setStartDate(startDate);
					cable.setMonthlySuscription(plan.getMonthlySuscription());
					cable.setDescription(plan.getDescription());
					cable.setStatus(Util.ACCOUNT_STATUS_ACTIVE);
					
					ArrayList<ChannelFeatureVO> features = ((CableTvVO)plan).getAllAddonChannel();
					int cnt = 3; int x = 0;
					while (cnt > 0) {
						if (features.get(x).getClass().equals(StandardChannelFeatureVO.class)) {
							StandardChannelFeatureVO channel = (StandardChannelFeatureVO) features.get(x);
							channel.setStartDate(startDate);
							cable.addStandardChannel(channel);
							cnt--;
						}
						x++;
						if (x==features.size()) {
							x = 0;
						}
					}
					
					ChannelFeatureVO addon = features.get(features.size()-1);
					addon.setStartDate(startDate);
					cable.addChannel(addon);
					createSubscription(cable);
				}
				else if (plan.getName().equals(Util.SUBSCRIPTIONVO_DIGITALVOICE)) {
					
				}
				else {
					
				}
			}
		}
		
		// get subscriptionPlan, fillinVO, , getSubscription, add new feature, update
		// randomly set start between now and 15mths ago. 
		// randomly terminate 1 feature to current date, and 0-2 mths later
		// create 50 entries
		// printDb
	}

}
